//promise有三种状态，等待pending，成功fulfilled，失败rejected
const PANDING = "pending"
const FULFILLED = "fulfilled"
const REJECTED = "rejected"

class MyPromise{    //Promise是一个类
    // 定义一个执行器，需要接受两个参数，成功回调resolve，失败回调reject,并且立即执行
    constructor(executor) {
        try{ //捕获错误
            executor(this.resolve, this.reject)
        }catch(e){
            this.reject(e)
        }
    }
    status = PANDING // 默认状态是等待panding
    // 成功和失败的值
    value = undefined //默认undefined
    reason = undefined //默认undefined
    // 成功和失败回调,可以存储多个回调函数
    successCallbackList = []
    failCallbackList = []
    // 执行器中的resolve
    resolve = (value) => {
        if(this.status != PANDING) { return } //禁止重复更改状态
        this.status = FULFILLED //状态改为成功
        this.value = value
        while(this.successCallbackList.length){ //依次执行成功回调中的方法
            this.successCallbackList.shift()()
        }
    }
    // 执行器中的rejected
    reject = (reason) => {
        if(this.status != PANDING) { return } //禁止重复更改状态
        this.status = REJECTED  //状态改为失败
        this.reason = reason
        while(this.failCallbackList.length){
            this.failCallbackList.shift()()
        }
    }
    then = (successCallback, failCallback) => { //then方法接收成功回调和失败回调
        successCallback = successCallback? successCallback: value => value //当没有传递成功回调
        failCallback = failCallback? failCallback: reason => { throw reason }//当没有传递失败回调
        // 返回MyPromise实例，以供链式调用
        let promise2 = new MyPromise((resolve, reject) => {
            if(this.status === FULFILLED){  //同步操作
                let st = setTimeout(() => { //setTimeout保证使用promise2时，promise已经返回了值
                    clearTimeout(st)
                    try{    //捕获错误
                        let x = successCallback(this.value)
                        resolvePromise(x, promise2, resolve, reject)
                    }catch(e) {
                        reject(e)
                    }
                }, 0)
            }else if(this.status === REJECTED){  //同步操作
                let st = setTimeout(() => { //setTimeout保证使用promise2时，promise已经返回了值
                    clearTimeout(st)
                    try{    //捕获错误
                        let x = failCallback(this.reason)
                        resolvePromise(x, promise2, resolve, reject)
                    }catch(e) {
                        reject(e)
                    }
                }, 0)
            }else{  //异步操作
                this.successCallbackList.push(() => { //将多个成功回调都记录到数组中
                    let st = setTimeout(() => { //setTimeout保证使用promise2时，promise已经返回了值
                        clearTimeout(st)
                        try{    //捕获错误
                            let x = successCallback(this.value)
                            resolvePromise(x, promise2, resolve, reject)
                        }catch(e) {
                            reject(e)
                        }
                    }, 0)
                })
                this.failCallbackList.push(() => { //将多个失败回调都记录到数组中
                    let st = setTimeout(() => { //setTimeout保证使用promise2时，promise已经返回了值
                        clearTimeout(st)
                        try{    //捕获错误
                            let x = failCallback(this.reason)
                            resolvePromise(x, promise2, resolve, reject)
                        }catch(e) {
                            reject(e)
                        }
                    }, 0)
                })
            }
        })
        return promise2
    }
    finally = callback => { //1.无论promise成功还是失败都会执行一次；2.finally后面可以继续then链式掉用
        return this.then(value => { //then知道promise状态&then返回promise对象
            return MyPromise.resolve(callback()).then(() => value) //执行callback，不管返回值是什么，都转成promise，然后执行promise
        }, reason => {
            return MyPromise.resolve(callback()).then(() => {throw reason})
        })
    }
    catch = failCallback => { //catch只接收失败回调
        return this.then(undefined, failCallback)
    }
    // resolve静态方法，如果是promise对象，直接返回，如果是普通值，需要转成promise对象
    static resolve(value) {
        if(value instanceof MyPromise){
            return value
        }else{
            return new MyPromise(resolve => resolve(value))
        }
    }
    // 传入失败的原因， 返回一个肯定失败的promise对象
    static reject(reason) {
        return new MyPromise((resolve, reject) =>  reject(reason))
    }
    // all在调用的时候是Promise.all(),所以all是静态方法
    // all等到所有方法成功执行完毕之后返回一个具有所有返回值的数组
    // all中如果有一个执行失败，直接进入reject
    static all(array) {
        let result = []
        let index = 0
        return new MyPromise((resolve, reject) => {
            function add(key, value) {  //存储结果
                result[key] = value
                index++
                if(index === array.length){ //all中可能有异步操作，需要保证所有异步操作都执行完了
                    resolve(result)
                }
            }
            for(let i = 0; i < array.length; i++) {
                let current = array[i] //当前值
                if(array[i] instanceof MyPromise){  //是否是promise对象
                    current.then(value => add(i, value), reason => reject(reason))
                }else{  //普通值
                    add(i, current)
                }
            }          
        })
    }
    // race是静态方法
    // 只要其中一个方法有返回就直接返回其结果
    static race(array) {
        return new MyPromise((resolve, reject) => {
            function add(value) {
                resolve(value)  //直接返回结果
            }
            for(let i= 0; i < array.length; i++) {
                let current = array[i] //当前值
                if(array[i] instanceof MyPromise){  //是否是promise对象
                    current.then(value => add(value), reason => reject(reason))
                }else{  //普通值
                    add(current)
                }
            }
        })
    }
    // allSettled返回包括成功和失败的全部执行结果，每个结果对象，都有一个status字符串
    static allSettled(array) {
        let result = []
        let index = 0
        return new MyPromise((resolve, reject) => {
            function add(key, value){   //此处同MyPromise.all
                result[key] = value
                index ++
                if(index === array.length){
                    resolve(result)
                }
            }
            for(let i = 0; i < array.length; i++) {
                let current = array[i]
                if(current instanceof MyPromise){ //成功和失败都返回结果
                    current.then(value => add(i, {status: current.status, value: value}),
                                reason => add(i, {status: current.status, reason: reason}))
                }else{  //普通值直接返回成功
                    add(i, {status: FULFILLED, value: current})
                }                
            }
        })
    }
}

function resolvePromise(x, promise2, resolve, reject) {
    if(x === promise2){ //判断是否自己返回自己
        return reject(new TypeError('Chaining cycle detected for promise #<Promise>'))
    }
    if( x instanceof MyPromise){    //promise对象查看状态，并传给下一个promise对象
        x.then(resolve, reject)
    }else{  //普通值，直接通过resolve传递
        resolve(x)
    }
}

module.exports = MyPromise